/*  
*   This file is a part of Neutrino - a lightweight UI library accelerated with OpenGL
*   Copyright (C) 2023 bsolos
*
*   This program is free software: you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation, either version 3 of the License, or
*   (at your option) any later version.
*
*   This program is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once

#include <string>
#include <unordered_map>

// massive uniform method generator
#define GEN_ARGS1(ctype) ctype v0
#define GEN_ARGS2(ctype) GEN_ARGS1(ctype), ctype v1
#define GEN_ARGS3(ctype) GEN_ARGS2(ctype), ctype v2
#define GEN_ARGS4(ctype) GEN_ARGS3(ctype), ctype v3

#define UNIFORM_METHOD_BODY(argc, glsuff) ;

#define UNIFORM_METHOD(ns, gltype, ctype, argc, glsuff) void ns uniform_##gltype(std::string uniform, GEN_ARGS##argc(ctype)) UNIFORM_METHOD_BODY(argc, glsuff)

#define GEN_VECTOR_METHODS(ns, glpfx, ctype, glsuff) \
UNIFORM_METHOD(ns, glpfx ## vec2, ctype, 2, glsuff) \
UNIFORM_METHOD(ns, glpfx ## vec3, ctype, 3, glsuff) \
UNIFORM_METHOD(ns, glpfx ## vec4, ctype, 4, glsuff)

#define SCALAR_UNIFORM_METHODS(ns) \
UNIFORM_METHOD(ns, bool, bool, 1, i) \
UNIFORM_METHOD(ns, int, int32_t, 1, i) \
UNIFORM_METHOD(ns, float, float, 1, f)

#define VECTOR_UNIFORM_METHODS(ns) \
GEN_VECTOR_METHODS(ns, i, int32_t, i) \
GEN_VECTOR_METHODS(ns, , float, f)

#define UNIFORM_METHODS(ns) \
SCALAR_UNIFORM_METHODS(ns) \
VECTOR_UNIFORM_METHODS(ns)

namespace neutrino {
    class render_context;

    class shader {
    public:
        shader(render_context *ctx, char *vertex_src, char *fragment_src);
        ~shader();

        void use();

        UNIFORM_METHODS()

    protected:
        GLint program;

        render_context *ctx;

        std::unordered_map<std::string, void*> uniforms;
        std::unordered_map<std::string, GLint> uniform_locations;

        GLint uniform_location(std::string uniform);
    };
}

#ifndef NO_UNDEF_UNIFORM_METHOD_GENERATOR
#undef UNIFORM_METHODS
#undef VECTOR_UNIFORM_METHODS
#undef SCALAR_UNIFORM_METHODS
#undef GEN_VECTOR_METHODS
#undef UNIFORM_METHOD
#undef UNIFORM_METHOD_BODY
#undef GEN_ARGS4
#undef GEN_ARGS3
#undef GEN_ARGS2
#undef GEN_ARGS1
#endif
